<template>
  <div class="dept">
    <div class="dept-header">部门列表</div>
    <div class="dept-tree">
      <el-tree
        v-if="deptTree"
        :data="deptTree"
        :default-expanded-keys="['-1', '0']"
        :allow-drop="allowDrop"
        :allow-drag="allowDrag"
        @node-drop="nodeDrop"
        draggable
        node-key="id"
        ref="deptTree"
        highlight-current
        @node-click="onDeptSelected"
      >
        <div draggable="true" class="custom-tree-node" slot-scope="{ node,data }">
          <div class="node-item">
            <div class="icon">
              <img v-if="isSubMenu(data)" width="20" height="20" src="/static/img/user/dept.png" />
              <img v-else width="20" height="20" src="/static/img/user/dept-group.png" />
            </div>
            <div class="label">{{data.name}}</div>
            <div class="actions" @click.stop>
              <div class="action-item" @click="addDept(data)">
                <i class="el-icon-plus"></i>
              </div>

              <div class="action-item" v-if="data.id !== 0" @click="editDept(data)">
                <i class="el-icon-edit"></i>
              </div>

              <div class="action-item" v-if="isSubMenu(data)" @click="deleteDept(data, node)">
                <i class="el-icon-delete"></i>
              </div>
            </div>
          </div>
        </div>
      </el-tree>
    </div>

    <el-dialog title="编辑部门信息" width="500px" :visible.sync="deptEditorVisible">
      <el-form
        ref="deptForm"
        @submit.native="saveDept()"
        :model="deptForm"
        :rules="deptFormRules"
        label-width="100px"
      >
        <el-form-item label="上级部门" prop="parenId">
          <el-cascader
            :disabled="!deptForm.isEdit"
            clearable
            filterable
            :options="cascaderTree"
            v-model="deptParentIdList"
            :props="{
                label: 'name',
                value: 'id',
                checkStrictly: true
              }"
            style="width:100%"
          ></el-cascader>
        </el-form-item>

        <el-form-item label="部门名称" prop="name">
          <el-input v-model="deptForm.name"></el-input>
        </el-form-item>
      </el-form>

      <div slot="footer">
        <el-button type="default" @click="closeEditor()">取消</el-button>
        <el-button type="primary" @click="saveDept()">保存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { treeDataTranslate } from '@/utils'

export default {
  name: 'deptMenu',
  data() {
    return {
      deptParentIdList: [],
      cascaderTree: [],
      deptTree: [],
      deptForm: {
        id: '',
        parentName: '',
        parentId: '',
        name: '',
        sort: 0,
        isEdit: false
      },
      deptFormRules: {
        parentId: [
          { required: true, message: '请选择上级部门', trigger: 'blur' }
        ],
        name: [{ required: true, message: '请填写部门名称', trigger: 'blur' }]
      },
      deptEditorVisible: false,
      selectedDept: null,
      treeUpdatedCallback: () => {}
    }
  },
  methods: {
    addDept(parentDept) {
      this.deptEditorVisible = true
      this.$refs.deptForm && this.$refs.deptForm.resetFields()

      this.deptForm.id = ''
      this.deptForm.name = ''
      this.deptForm.sort = 0
      this.deptForm.parentId = parentDept.id
      this.deptForm.parentName = parentDept.name
      this.deptForm.isEdit = false
      this.initCascaderTree(this.deptForm.id, this.deptForm.parentId)

      this.treeUpdatedCallback = async () => {
        let children = await this.getDeptListByParentId(parentDept.id)
        if (children && children.length > 0) {
          let latestDept = children[children.length - 1]
          if (!parentDept.children) {
            this.$set(parentDept, 'children', [])
          }
          parentDept.children.push(latestDept)
        }
        this.$store.dispatch('user/loadDeptList')
      }
    },
    editDept(dept) {
      this.deptEditorVisible = true
      this.$refs.deptForm && this.$refs.deptForm.resetFields()
      var parentDept = this.deptList.find(x => x.id === dept.parentId)

      this.deptForm.id = dept.id
      this.deptForm.parentId = dept.parentId || 0
      this.deptForm.parentName = parentDept ? parentDept.name : '全部部门'
      this.deptForm.name = dept.name
      this.deptForm.sort = dept.sort
      this.deptForm.isEdit = true
      this.initCascaderTree(this.deptForm.id, this.deptForm.parentId)

      let originParentId = this.deptForm.parentId
      this.treeUpdatedCallback = () => {
        if (originParentId !== this.deptForm.parentId) {
          this.buildTree()
        } else {
          dept.name = this.deptForm.name
        }
      }
    },
    closeEditor() {
      this.deptEditorVisible = false
    },
    onDeptSelected(dept) {
      this.selectedDept = dept
      this.$emit('select', dept)
    },
    isSubMenu(dept) {
      if (dept.id === '0') return false
      if (dept.children && dept.children.length > 0) return false

      return true
    },
    allowDrop(draggingNode, dropNode, type) {
      if (draggingNode.data.parentId !== dropNode.data.parentId) {
        return false
      }
      return type !== 'inner'
    },
    allowDrag(draggingNode) {
      return true
    },
    nodeDrop(before, after, inner, event) {
      let newSort = 0
      let deptList = this.deptList.filter(
        x => x.parentId === after.data.parentId
      )
      let index = deptList.findIndex(x => x.id === after.data.id)
      if (index === 0) {
        newSort = after.data.sort - 10
      } else if (index === deptList.length - 1) {
        newSort = after.data.sort + 10
      } else {
        let start = deptList[index - 1].sort
        let end = after.data.sort
        newSort = ((start + end) / 2).toFixed(2)
      }
      let currentNode = deptList.find(x => x.id === before.data.id)
      this.sortDept(currentNode, newSort)
    },
    async deleteDept(dept, node) {
      let confirm = await this.$confirm(
        `您确认要删除${dept.name}部门吗？`,
        '提示',
        {
          confirmButtonText: '确认',
          cancelButtonText: '取消'
        }
      )

      if (confirm !== 'confirm') return
      let res = await this.$http.post(
        `/usercenter-admin/dept/delete/${dept.id}`
      )
      if (res && res.code === 200) {
        // 删除节点
        let parentDept = node.parent.data
        let index = parentDept.children.findIndex(x => x.id === dept.id)
        parentDept.children.splice(index, 1)

        // 通知
        this.$notify.success({ title: '成功', message: '删除部门成功' })
        this.onDeptSelected(null)
        this.$store.dispatch('user/loadDeptList')
      } else {
        this.$notify.error({ title: '错误', message: res.msg })
      }
    },
    async getDeptListByParentId(parentId) {
      let res = await this.$http.post(
        '/usercenter-admin/dept/getparentdeptlist',
        {
          parentId: parentId
        }
      )
      return res.data
    },
    async saveDept() {
      let valid = await this.$refs.deptForm.validate()
      if (!valid) return

      let isEdit = this.deptForm.isEdit

      // 新增时设置排序
      if (!isEdit) {
        let sort = 0
        let subDeptList = this.deptList.filter(
          x => x.parentId === this.deptForm.parentId
        )
        if (subDeptList.length > 0) {
          // 新增子节点
          let sortList = subDeptList.map(x => x.sort).sort((a, b) => b - a)
          sort = sortList[0] + 10
        } else {
          // 新增根节点
          let rootDeptList = this.deptList.filter(x => x.parentId === '0')
          let sortList = rootDeptList.map(x => x.sort).sort((a, b) => b - a)
          sort = sortList.length > 0 ? sortList[0] + 10 : 10
        }
        this.deptForm.sort = sort
      }

      var res = await this.$http.post(
        `/usercenter-admin/dept/${isEdit ? 'update' : 'save'}`,
        {
          id: this.deptForm.id,
          name: this.deptForm.name,
          parentId: this.deptForm.parentId,
          sort: this.deptForm.sort
        }
      )

      if (res && res.code === 200) {
        this.treeUpdatedCallback()
        this.closeEditor()
        this.$store.dispatch('user/loadDeptList')
        this.$notify.success({ title: '成功', message: '保存部门成功' })
      }
    },
    async sortDept(dept, newSort) {
      await this.$http.post('/usercenter-admin/dept/update', {
        id: dept.id,
        name: dept.name,
        parentId: dept.parentId,
        sort: newSort
      })
      await this.$store.dispatch('user/loadDeptList')
      this.$notify.success({ title: '成功', message: '部门排序成功' })
    },
    async buildTree() {
      await this.$store.dispatch('user/loadDeptList')
      let temp = JSON.parse(JSON.stringify(this.deptList))
      temp.push({
        id: '0',
        name: '全部部门',
        parentId: '-1'
      })
      this.deptTree = treeDataTranslate(temp, 'id', 'parentId')

      // 默认选中根节点
      let root = this.deptTree[0]
      this.onDeptSelected(root)
      this.$nextTick(() => {
        this.$refs.deptTree.setCurrentKey(root.id)
      })
    },
    async buildCascaderTree(disabledId) {
      // await this.$store.dispatch('user/loadDeptList')
      let temp = JSON.parse(JSON.stringify(this.deptList))
      temp.push({
        id: '0',
        name: '全部部门',
        parentId: '-1'
      })
      this.cascaderTree = treeDataTranslate(temp, 'id', 'parentId', [
        disabledId
      ])
    },
    initCascaderTree(currentId, parentId) {
      this.buildCascaderTree(currentId)
      var arr = []
      var tempParentId = parentId
      while (tempParentId > 0) {
        arr.splice(0, 0, tempParentId)
        let parent = this.deptList.find(x => x.id === tempParentId)
        if (!parent || parent.parentId === tempParentId) {
          break
        }
        tempParentId = parent.parentId
      }
      arr.splice(0, 0, '0')
      this.deptParentIdList = arr
    }
  },
  computed: {
    deptList() {
      return this.$store.getters['user/deptList']
    }
  },
  async mounted() {
    await this.buildTree()
  },
  watch: {
    deptParentIdList(val) {
      this.deptForm.parentId = val[val.length - 1]
    }
  }
}
</script>

<style lang="less">
.dept {
  height: 100%;
  width: 300px;
  border-right: 2px solid #eee;

  .add-dept-button {
    background-color: #409eff;
    height: 46px;
  }

  .dept-header {
    height: 40px;
    text-align: center;
    line-height: 40px;
    border-bottom: 1px solid #eee;
  }

  .dept-tree {
    height: calc(~'100% - 40px');
    overflow-y: auto;
    padding: 5px 0;

    .el-tree-node__content {
      height: 40px;
    }

    .custom-tree-node {
      .node-item {
        display: flex;

        .label {
          margin-left: 12px;
          line-height: 20px;
          width: 80px;
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
        }

        .actions {
          display: flex;
          margin-left: 10px;

          .action-item {
            height: 20px;
            width: 20px;
            margin-right: 6px;
          }
        }
      }
    }
  }

  .user-list {
    flex: auto;
  }
}
</style>
